#include "Vec3.h"
#include "Error.h"
#include <cmath>

namespace Engine
{
	Vec3::Vec3():x(0.0f), y(0.0f), z(0.0f){}

	Vec3::Vec3(float _x, float _y, float _z):x(_x), y(_y), z(_z){}

	Vec3& Vec3::operator+=(const Vec3& rhs)
	{
		x += rhs.x;
		y += rhs.y;
		z += rhs.z;
	
		return (*this);
	}


	
	Vec3& Vec3::operator+=(float a)
	{
		x += a;
		y += a;
		z += a;
	
		return (*this);
	}
	
	Vec3 Vec3::operator+(const Vec3& rhs) const
	{
		Vec3 temp = (*this);
		temp += rhs;
	
		return temp;
	}
	
	Vec3 Vec3::operator+(float a) const
	{
		Vec3 temp = (*this);
		temp += a;
	
		return temp;
	}
	
	Vec3& Vec3::operator-=(const Vec3& rhs)
	{
		x -= rhs.x;
		y -= rhs.y;
		z -= rhs.z;
	
		return (*this);
	}
	
	Vec3 Vec3::operator-(const Vec3& rhs) const
	{
		Vec3 temp = (*this);
		temp -= rhs;
	
		return temp;
	}
	
	Vec3& Vec3::operator-=(float a)
	{
		x -= a;
		y -= a;
		z -= a;
	
		return (*this);
	}
	
	Vec3 Vec3::operator-(float a) const
	{
		Vec3 temp = (*this);
		temp -= a;
	
		return temp;
	}

	Vec3 Vec3::operator-() const {return Vec3(-x, -y, -z);}
	
	Vec3& Vec3::operator*=(float a)
	{
		x *= a;
		y *= a;
		z *= a;
	
		return (*this);
	}

	Vec3 Vec3::operator*(float a) const {return Vec3(x * a, y * a, z * a);}
	
	Vec3& Vec3::operator*=(Vec3& rhs)
	{
		x *= rhs.x;
		y *= rhs.y;
		z *= rhs.z;
	
		return (*this);
	}
	
	Vec3 Vec3::operator*(Vec3& rhs) const
	{
		Vec3 temp = (*this);
		temp *= rhs;
	
		return temp;
	}

	Vec3 Vec3::operator/(float a) const
	{
		Vec3 temp = (*this);
		temp /= a;
	
		return temp;
	}

	Vec3& Vec3::operator/=(float a)
	{
		x /= a;
		y /= a;
		z /= a;
	
		return (*this);
	}

	float& Vec3::operator[](unsigned int index)
	{
		switch(index)
		{
			case 0:
				return x;

			case 1:
				return y;

			case 2:
				return z;

				//to stop compiler warnings, this will never get executed
			default:
				Error("Attempting to access a non existing member of Vec3");
				return z;
		}
	}

	float* Vec3::ToArray(){return &x;}

	float Vec3::Length() const {return std::sqrtf(x*x + y*y + z*z);}
	
	void Vec3::Normalize()
	{
		float oneOverLength = 1.0f / std::sqrtf(x*x + y*y + z*z);
		(*this) *= oneOverLength;
	}

	float Vec3::SquaredLength() const {return (x*x + y*y + z*z);}
	
	float DotProduct(const Vec3& a, const Vec3& b)
	{
		return ((a.x * b.x) + (a.y * b.y) + (a.z * b.z));
	}
	
	Vec3 CrossProduct(const Vec3& a, const Vec3& b)
	{
		return Vec3(((a.y * b.z) - (a.z * b.y)),
			((a.z * b.x) - (a.x * b.z)),
			((a.x * b.y) - (a.y * b.x)));
	}

}
